package org.keyroy.util.tag;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

/**
 * http://zcy860511.iteye.com/blog/585900
 * 
 * @author keyroy
 * 
 */
public class SimpleXmlObject extends XmlObject {

	@SuppressWarnings("unchecked")
	@Override
	public void initTag(Tag tag) {
		Field[] fields = getClass().getFields();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			try {
				Class<?> fClass = field.getType();
				if (isSubClass(fClass, List.class)) {
					ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
					Type type = parameterizedType.getActualTypeArguments()[0];
					if (isSubClass(type, XmlSupport.class)) {
						List<XmlSupport> list = (List<XmlSupport>) field.get(this);
						tag.addChild(list);
					}
				} else if (isSubClass(fClass, Hashtable.class)) {
					ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
					Type type = parameterizedType.getActualTypeArguments()[1];
					if (isSubClass(type, XmlSupport.class)) {
						Hashtable<?, XmlSupport> table = (Hashtable<?, XmlSupport>) field.get(this);
						tag.addChild(table.elements());
					}
				} else {
					Parser parser = baseClassTable.get(fClass);
					if (parser != null) {
						Object value = field.get(this);
						if (value != null) {
							tag.addParameter(field.getName(), String.valueOf(value));
						}
					} else if (isSubClass(fClass, XmlSupport.class)) {
						XmlSupport object = (XmlSupport) field.get(this);
						tag.addChild(object);
					}
				}
			} catch (Exception e) {
			}
		}
	}

	@SuppressWarnings({ "unchecked" })
	@Override
	public void initObj(Tag tag) {
		Field[] fields = getClass().getFields();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			try {
				Class<?> fClass = field.getType();
				if (isSubClass(fClass, List.class)) {
					ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
					Type type = parameterizedType.getActualTypeArguments()[0];
					if (isSubClass(type, XmlSupport.class)) {
						List<XmlSupport> list = (List<XmlSupport>) field.get(this);
						if (list == null) {
							list = new ArrayList<XmlSupport>();
							field.set(this, list);
						}

						tag.getChildObjectArray((Class<? extends XmlSupport>) type, list);

						if (list instanceof ArrayList<?>) {
							((ArrayList<?>) list).trimToSize();
						}

					}
				} else if (isSubClass(fClass, Hashtable.class)) {
					ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
					Type type = parameterizedType.getActualTypeArguments()[1];
					if (isSubClass(type, XmlSupport.class)) {
						List<XmlSupport> list = tag.getChildObjectArray((Class<? extends XmlSupport>) type);
						for (int j = 0; j < list.size(); j++) {
							findHashtableElement(list.get(j));
						}
					}
				} else {
					Parser parser = baseClassTable.get(fClass);
					if (parser != null) {
						String value = tag.getParameterValue(field.getName());
						if (value != null) {
							field.set(this, parser.parser(value));
						}
					} else if (isSubClass(fClass, XmlSupport.class)) {
						XmlSupport support = ((XmlSupport) field.get(this));
						if (support == null) {
							try {
								support = ((XmlSupport) (fClass.newInstance()));
							} catch (Exception e) {
							}
						}
						Tag cTag = tag.getChildTag(support.getTagName(), true);
						if (cTag != null) {
							support.initObj(cTag);
							field.set(this, support);
						}
					}
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private final boolean isSubClass(Class<?> childClass, Class<?> superClass) {
		return childClass.equals(superClass) || superClass.isAssignableFrom(childClass);
	}

	private final boolean isSubClass(Type type, Class<?> superClass) throws ClassNotFoundException {
		Class<?> class1 = Class.forName(type.toString().replace("class ", ""));
		return isSubClass(class1, superClass);
	}

	protected void findHashtableElement(XmlSupport xmlSupport) {

	}

	private static Hashtable<Class<?>, Parser> baseClassTable = new Hashtable<Class<?>, Parser>();
	static {
		baseClassTable.put(int.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Integer.parseInt(s);
			}
		});
		baseClassTable.put(long.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Long.parseLong(s);
			}
		});
		baseClassTable.put(float.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Float.parseFloat(s);
			}
		});
		baseClassTable.put(double.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Double.parseDouble(s);
			}
		});
		baseClassTable.put(boolean.class, new Parser() {

			@Override
			public Object parser(String s) {
				return Boolean.parseBoolean(s);
			}
		});

		baseClassTable.put(Integer.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Integer.parseInt(s);
			}
		});
		baseClassTable.put(Long.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Long.parseLong(s);
			}
		});
		baseClassTable.put(Float.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Float.parseFloat(s);
			}
		});
		baseClassTable.put(Double.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Double.parseDouble(s);
			}
		});
		baseClassTable.put(Boolean.class, new Parser() {
			@Override
			public Object parser(String s) {
				return Boolean.parseBoolean(s);
			}
		});

		baseClassTable.put(String.class, new Parser() {
			@Override
			public Object parser(String s) {
				return s;
			}
		});

	}

	private interface Parser {
		public Object parser(String s);
	}

}
